package com.nami.dispatcher.infra.gateway;


import cn.hutool.core.collection.CollUtil;
import com.nami.basic.dto.MultiResponse;
import com.nami.basic.dto.Response;
import com.nami.basic.dto.SingleResponse;
import com.nami.dispatcher.domain.gateway.UserGateway;
import com.nami.dispatcher.infra.cache.user.caffeine.OnlUserCache;
import com.nami.dispatcher.infra.cache.user.convert.UserConvert;
import com.nami.gate.external.basic.cache.user.UserSessionRel;
import com.nami.gate.external.basic.cache.user.DeviceInfo;
import com.nami.gate.external.basic.cache.user.UserDeviceRel;
import com.nami.ucenter.client.api.UserReadClient;
import com.nami.ucenter.client.request.UserDeviceDelCmd;
import com.nami.ucenter.client.response.UserWithDeviceInfoDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UserGatewayImpl implements UserGateway {

    @DubboReference
    UserReadClient userClient;

//    @Deprecated
//    public UserWithDeviceInfo getUserById(String appKey, String userId) {
//        if (StringUtils.isBlank(appKey) || StringUtils.isBlank(userId)) {
//            return null;
//        }
//        UserWithDeviceInfo user = UserCache.get(userId);
//        if (user == null) {
//            RLock lock = RedisUtils.getClient().getLock("nami:" + appKey + ":user:lock:" + userId);
//            try {
//                lock.lock();
//                // 只要登录了。就存入了redis

    ////                UserWrap exist = cacheService.getOnrUser(appKey, userId);
//                SingleResponse<UserCO> response = userReadFacade.getByUserId(appKey, userId);
//                if (!response.isSuccess()) {
//                    return null;
//                }
//                UserCO exist = response.getData();
//                if (exist == null) {
//                    return null;
//                }
//                UserWithDeviceInfo userWrap = new UserWithDeviceInfo();
//                userWrap.setUserId(userId);
//                userWrap.setAppKey(exist.getAppKey());
//                userWrap.setNick(exist.getNickname());
//                userWrap.setAvatar(exist.getAvatarUrl());
//                userWrap.setStatus(exist.getStatus());
//
//                UserCache.add(userId, userWrap);
//                return userWrap.clone();
//            } finally {
//                lock.unlock();
//            }
//        }
//        return user;
//    }
    public List<DeviceInfo> getOnlineDevicesExceptThisDevice(String appKey, String userId, String instanceId) {
        List<DeviceInfo> deviceInfos = getOnlineDevicesByUserId(appKey, userId);
        if (CollUtil.isNotEmpty(deviceInfos)) {
            List<DeviceInfo> result = deviceInfos.stream().filter(item -> !item.getInstanceId().equals(instanceId)).collect(Collectors.toList());
            return result;
        }
        return null;
    }

    public List<DeviceInfo> getOnlineDevicesByUserId(String appKey, String userId) {
        UserDeviceRel userWrap = OnlUserCache.get(userId);
        if (userWrap == null) {
            // TODO 是否需要锁住

            SingleResponse<UserWithDeviceInfoDTO> response = userClient.getUserInfoFromCacheOrDB(appKey, userId);
            if (response.isSuccess()) {
                UserWithDeviceInfoDTO data = response.getData();
                if (data == null) {
                    return null;
                }
                UserDeviceRel wrap = UserConvert.INSTANCE.toWrap(data);
                OnlUserCache.add(userId, wrap);
                return wrap.getDeviceInfos();
            }
            return null;

        }
        List<DeviceInfo> deviceInfos = userWrap.getDeviceInfos();
        if (CollUtil.isEmpty(deviceInfos)) {
            return null;
        }
        return deviceInfos;
    }

    public UserDeviceRel getOnlUserDetailInfoById(String appKey, String userId) {
        if (StringUtils.isBlank(appKey) || StringUtils.isBlank(userId)) {
            return null;
        }
        UserDeviceRel user = OnlUserCache.get(userId);
        if (user == null) {
            SingleResponse<UserWithDeviceInfoDTO> userDto = userClient.getUserInfoFromCacheOrDB(appKey, userId);
            if (userDto.isSuccess()) {
                UserWithDeviceInfoDTO data = userDto.getData();
                if (data == null) {
                    return null;
                }
                UserDeviceRel wrap = UserConvert.INSTANCE.toWrap(data);
                OnlUserCache.add(userId, wrap);
                return wrap;
            }

        }
        return user;
    }

    public Map<String, List<UserSessionRel>> getOnlineDevicesByMqTagsClassification(String appKey, List<String> userIds) {
        List<UserSessionRel> allDevices = new ArrayList<>();
        List<String> qryUserIds = new ArrayList<>();
        for (String userId : userIds) {
            UserDeviceRel user = OnlUserCache.get(userId);
            if (user == null) {
                qryUserIds.add(userId);
                continue;
            }
            List<DeviceInfo> deviceInfos = user.getDeviceInfos();
            if (CollUtil.isEmpty(deviceInfos)) {
                continue;
            }
            UserSessionRel deviceInfo;
            for (DeviceInfo item : deviceInfos) {
                deviceInfo = new UserSessionRel();
                deviceInfo.setAppKey(appKey);
                deviceInfo.setPlatform(item.getPlatform());
                deviceInfo.setUserId(userId);
                deviceInfo.setConnectId(item.getConnectId());
                deviceInfo.setInstanceId(item.getInstanceId());
                deviceInfo.setUserIp(item.getUserIp());
                allDevices.add(deviceInfo);
            }
        }

        if (qryUserIds.size() > 0) {
            MultiResponse<UserDeviceRel> response = userClient.listUsersWithAttachedDevicesWhenOnline(appKey, qryUserIds);
            if (response.isSuccess()) {
                List<UserDeviceRel> users = response.getData();
                if (CollUtil.isNotEmpty(users)) {
                    UserSessionRel deviceInfo;
                    for (UserDeviceRel user : users) {
                        if (user == null) {
                            continue;
                        }
                        OnlUserCache.add(user.getUserId(), user);
                        deviceInfo = new UserSessionRel();
                        deviceInfo.setAppKey(appKey);
                        deviceInfo.setUserId(user.getUserId());
                        List<DeviceInfo> deviceInfos = user.getDeviceInfos();
                        if (CollUtil.isEmpty(deviceInfos)) {
                            continue;
                        }
                        for (DeviceInfo info : deviceInfos) {
                            deviceInfo.setPlatform(info.getPlatform());
                            deviceInfo.setConnectId(info.getConnectId());
                            allDevices.add(deviceInfo);
                        }

                    }

                }
            }
        }

        Map<String, List<UserSessionRel>> result = allDevices
            .stream()
            .collect(Collectors.groupingBy(UserSessionRel::getConnectId));
        return result;
    }

    public boolean removeOfflineDevice(String appKey, String userId, String instanceId) {
        UserDeviceDelCmd cmd = UserDeviceDelCmd.builder()
            .appKey(appKey)
            .userId(userId)
            .instanceId(instanceId)
            .build();
        Response response = userClient.removeOfflineDevice(cmd);
        if (response == null) {
            return Boolean.FALSE;
        }
        return response.isSuccess();
    }

    public void markOnlineUserInvalid(String userId) {
        OnlUserCache.del(userId);
    }

}
